#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <cstring>
#include <strings.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "ThreadPoolSingle.hpp"
#include "log.hpp"
#include "task.hpp"


enum err
{
    SocketErr = 1,
    BindErr,
    ListenErr,
};

int backlog = 10;
uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";

class TcpServer;

class ThreadData
{
public:
    ThreadData(int sockfd, const uint16_t &clientport, const std::string clientip, TcpServer *t)
        : sockfd_(sockfd), port_(clientport), ip_(clientip), tser_(t)
    {
    }

public:
    int sockfd_;
    uint16_t port_;
    std::string ip_;
    TcpServer *tser_;
};

class TcpServer
{
public:
    TcpServer(uint16_t port = defaultport, std::string ip = defaultip)
        : port_(port),
          ip_(ip)
    {
    }
    int Init()
    {
        // 创建套接字
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            lg(FATAL, "Socket Error,errno:%d,error", errno, strerror(errno));
            return SocketErr;
        }
        lg(INFO, "Socket Success");

        int opt = 1;
        setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

        // bind
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &server.sin_addr);

        int bindn = bind(sockfd_, (struct sockaddr *)&server, sizeof(server));
        if (bindn < 0)
        {
            lg(FATAL, "Bind Error,errno:%d,error:%s", errno, strerror(errno));
            return BindErr;
        }
        lg(INFO, "Bind Success");

        // 监听
        int listenn = listen(sockfd_, backlog);
        if (listenn < 0)
        {
            lg(FATAL, "Listen Error,errno:%d,error:%s", errno, strerror(errno));
            return ListenErr;
        }
        lg(INFO, "Listen Success");
    }
    void Run()
    {
        lg(INFO, "TCP running...");
        ThreadPool<Task>::GetInstance()->start();
        lg(INFO,"ThreadPool Start...");
        for (;;)
        {
            struct sockaddr_in client;
            bzero(&client, sizeof(client));
            socklen_t clientlen = sizeof(client);
            int sockfd = accept(sockfd_, (struct sockaddr *)&client, &clientlen);
            if (sockfd < 0)
            {
                // lg(WARNING, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }

            uint16_t clientport = ntohs(client.sin_port);
            char clientip1[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip1, sizeof(client));
            std::string clientip = clientip1;

            lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);

            // version - 单进程
            // SingleProcess(sockfd, clientport, clientip);

            // 多进程
            //MultiProcess(sockfd, clientport, clientip);

            // 多线程
            //MultiThreads(sockfd, clientport, clientip);

            //线程池
            ThreadPolls(sockfd, clientport, clientip);
        }
    }

    void Service(int sockfd, const uint16_t &clientport, const std::string clientip)
    {
        char buffer[4096];
        while (true)
        {
            ssize_t n = read(sockfd, &buffer, sizeof(buffer));
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << "Client say# " << buffer << std::endl;
                std::string echo = "TcpServer ehco# ";
                echo += buffer;

                write(sockfd, echo.c_str(), echo.size());
            }
            else if (n == 0)
            {
                lg(INFO, "Server Quit..");
                break;
            }
            else if (n < 0)
            {
                lg(WARNING, "read error");
                break;
            }
        }
    }

    // 单进程
    void SingleProcess(int sockfd, const uint16_t &clientport, const std::string clientip)
    {
        Service(sockfd, clientport, clientip);
        close(sockfd);
    }

    // 多进程
    void MultiProcess(int sockfd, const uint16_t &clientport, const std::string clientip)
    {
        pid_t id = fork();
        if (id == 0)
        {
            lg(INFO, "Child Process Create...");
            close(sockfd_);
            if (fork() > 0)
                exit(0); // 进程孤儿
            Service(sockfd, clientport, clientip);
            close(sockfd);
            exit(0);
        }
        // father
        close(sockfd);
        int n = waitpid(id, nullptr, 0);
        if (n > 0)
            lg(INFO, "Child Process Quit...");
    }

    // 多线程
    void MultiThreads(int sockfd, const uint16_t &clientport, const std::string& clientip)
    {
        pthread_t tid;
        ThreadData *td = new ThreadData(sockfd, clientport, clientip, this);
        pthread_create(&tid, nullptr, Routine, td);
    }
    static void *Routine(void *argv)
    {
        pthread_detach(pthread_self()); // 线程分离

        ThreadData *td = static_cast<ThreadData *>(argv);

        td->tser_->Service(td->sockfd_, td->port_, td->ip_);

        delete td;

        return nullptr;
    }

    //线程池
    void ThreadPolls(int sockfd, uint16_t &clientport,std::string clientip)
    {
        Task t(sockfd, clientport, clientip);
        ThreadPool<Task>::GetInstance()->push(t);
    }

    ~TcpServer()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }

private:
    int sockfd_;
    uint16_t port_;
    std::string ip_;
};